home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / Font Database / FontDBasePrerequisites.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  19.3 KB  |  707 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        FontDBasePrerequisites.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          File contains code to handle prerequisites for the fonts
  6.                         in the font database.
  7.  
  8.      Version:    Technology:    Quickdraw GX 1.1.x
  9.       
  10.      Copyright:    © 1991-1997 by Apple Computer, Inc., all rights reserved.
  11. */
  12.  
  13.  
  14. // allow multiple references to single label
  15. #define resumeLabel(exception)
  16. #include <MacMemory.h>
  17. #include <Resources.h>
  18. #include "GXExceptions.h"
  19. #include "GXPrintingUniverse.h"
  20. #include "IOUtilities.h"
  21.  
  22. #include <GXFonts.h>
  23.  
  24.  
  25. //#include <OFA1TypesPriv.h>
  26.  
  27. #ifndef __COLLECTIONMANAGER__
  28. #include <Collections.h>
  29. #endif
  30.  
  31. #ifndef __FONTDBASEHANDLER__
  32. #include "FontDatabase.h"
  33. #endif
  34.  
  35. #include "FontDBasePrivate.h"
  36.  
  37.      typedef struct {
  38.         gxSpoolBlock    spool;
  39.  
  40.         Handle        streamHdl;
  41.         long            count;
  42.         long            size;
  43.         OSErr            saveError;
  44.  
  45.     } userSpool;
  46.  
  47.  
  48. static long FDBSpoolProc(gxSpoolCommand command, struct gxSpoolBlock *block)
  49.     {
  50.     #pragma unused (command, block)
  51.     
  52.         /** do nothing **/
  53.         
  54.         return(0);
  55.     }
  56.  
  57.  
  58. /***********************************
  59.     Function: FDBStreamFont:
  60.     
  61.     Function is a wrapper for stream font.
  62.     If messaging is indicated, the message is sent.
  63.     If not, GXFlattenFont is called directly.
  64.     
  65. *************************************/
  66. OSErr    FDBStreamFont(gxFont theFont, scalerStream *pStreamRecord);
  67. OSErr    FDBStreamFont(gxFont theFont, scalerStream *pStreamRecord)
  68.     {
  69.         OSErr                        status;
  70.         gxSpoolBlock        dummyBlock;
  71.         unsigned char        dummyBuffer;
  72.         
  73.             
  74.         #if GENERATINGPOWERPC
  75.             RoutineDescriptor    fdbSpoolProc_RD = BUILD_ROUTINE_DESCRIPTOR(uppgxSpoolProcInfo, FDBSpoolProc);
  76.             gxSpoolUPP                fdbSpoolProc_UPP = (gxSpoolUPP) &fdbSpoolProc_RD;
  77.         #else
  78.             gxSpoolUPP                fdbSpoolProc_UPP = (gxSpoolUPP) FDBSpoolProc;
  79.         #endif
  80.  
  81.         dummyBlock.buffer = &dummyBuffer;
  82.         dummyBlock.bufferSize = 1;
  83.         dummyBlock.spoolProcedure = fdbSpoolProc_UPP;
  84.         GXFlattenFont(theFont, pStreamRecord, &dummyBlock);
  85.         
  86.         status = GXGetGraphicsError(nil);
  87.             
  88.     
  89.         ncheck(status);
  90.         return(status);
  91.     
  92.     }//FDBStreamFont
  93.  
  94.  
  95.  
  96. //<FF>
  97. /*****************************************
  98.  
  99.     Routine turns on and off inclusion of prerequisite
  100.     data for a font in the database.
  101.     
  102.     fontDbase:            the font database.
  103.     theFont:                The font to set it for.
  104.     exclude:                false for include, true for exclude.
  105.     
  106. *******************************************/
  107. OSErr    FontDbaseExcludePrerequisite(TFontDbase fontDbase, gxFont theFont, Boolean exclude)
  108.     {
  109.         OSErr                            status;
  110.         TfdbInfoFlags            fontFlags;                    // font's flags.
  111.  
  112.         /*** Get the font's flags ****/
  113.  
  114.         status = FontDbaseGetFontInfo(fontDbase, theFont, nil, nil, nil, &fontFlags);
  115.         nrequire(status, failed_GetInfo);
  116.         
  117.         /** Set or clear the prerequisite exclusion bit as indicated **/
  118.         
  119.         if (exclude)
  120.             fontFlags |= fdbExcludeFontPrereqs;
  121.         else
  122.             fontFlags &= ~fdbExcludeFontPrereqs;
  123.             
  124.         /** Now set the flags back in the font **/
  125.  
  126.         status = FontDbaseSetFontFlags(fontDbase, theFont, fontFlags);
  127.         nrequire(status, failed_SetFlags);
  128.         
  129. failed_SetFlags:        
  130. failed_GetInfo:
  131.  
  132.         return(status);
  133.     
  134.     }//_FontDbaseExcludePrerequisite
  135.  
  136.  
  137. //<FF>
  138. /**************************************
  139.     
  140.     Function: FDBUnionPrerequisiteList
  141.     
  142.     This function unions in a new prerequisite list
  143.     with the prerequisite collection.
  144.     
  145.     hDbase:            the handle to the font database.
  146.     theFont:        The font reference that was used to obtain the list.
  147.     listSize:        size in bytes of the new list.
  148.     list:                pointer to the list data.
  149.     
  150.         
  151. ****************************************/
  152. OSErr FDBUnionPrerequisiteList(TFontDbaseHdl hDbase, gxFont theFont, long listSize, unsigned char *list, long *count);
  153. OSErr FDBUnionPrerequisiteList(TFontDbaseHdl hDbase, gxFont theFont, long listSize, unsigned char *list, long *count)
  154.     {
  155.         OSErr                                        status;
  156.         unsigned char                        *inList;                        // Point into the list;
  157.         unsigned char                        *endList;                        // Pointer to end of list;
  158.         gxFontFormatTag                    fontFormat;                    // Get the font format.
  159.         scalerPrerequisiteItem    *item;                            // Pointer to the item.
  160.         Collection                            prerequisites;            // the prerequisite collection.
  161.         long                                        enumeration;
  162.         long                                        itemSize;
  163.  
  164.         fontFormat = GXGetFontFormat(theFont);
  165.         
  166.         inList = list;
  167.         endList = list + listSize;
  168.         
  169.         prerequisites = (*hDbase)->prerequisites;
  170.         
  171.         /*** Walk the list and add items to the collection as appropriate ***/
  172.         
  173.         while (inList < endList) {
  174.         
  175.             item = (scalerPrerequisiteItem*)inList;
  176.             
  177.             /**  compute size of item add the name length to the structure size. **/
  178.             
  179.             itemSize = 8 + item->name[0] + 1;                /** structure is two longs followd by a pascal string if it changes we die **/
  180.             
  181.             /** See if the item is already in the collection **/
  182.             
  183.             enumeration = item->enumeration;
  184.             status = GetCollectionItem(prerequisites, (CollectionTag)fontFormat, enumeration, nil, nil);
  185.  
  186.             /** If the item was not found, add it to the collection **/
  187.             
  188.             if (status == collectionItemNotFoundErr) {
  189.             
  190.                 /*****
  191.                     replace the enumeration in the structure with the font reference (a handy place to stick it)
  192.                     since we need the reference somewhere and we are already using the enumeration as the 
  193.                     collection item ID
  194.                 ******/
  195.                 item->enumeration = (long)theFont;
  196.                 
  197.                 status = AddCollectionItem(prerequisites, (CollectionTag)fontFormat, enumeration, itemSize, item);
  198.                 nrequire(status, failed_AddItem);
  199.                 
  200.                 *count += 1;                // Increment the count of how many prerequisites.
  201.             
  202.             } else if (status != noErr) {
  203.             
  204.                 /** some other error happened, get out of loop **/
  205.                 
  206.                 ncheck(status);
  207.                 break;
  208.             
  209.             }//end if
  210.             
  211.             /** Point to the next item in the list **/
  212.             
  213.             inList += itemSize;
  214.         
  215.         }//end while
  216.     
  217.  
  218. failed_AddItem:
  219.  
  220.         return(status);
  221.     
  222.     }//FDBUnionPrerequisiteList
  223.  
  224. //<FF>
  225. /*************************************
  226.  
  227.     Function:    FontDbaseBuildPrerequisiteList
  228.     
  229.     Function builds the internal list of the prerequisites
  230.     required for the set of document fonts.  This function can
  231.     be called over and over again with different stream types or
  232.     when new fonts have been added to the database.
  233.     Each time, the old list is tossed and a new one created.
  234.     
  235.     fontDbase:        the font database object.
  236.     streamTypes:    The stream types for which to build the prerequisite list.
  237.     useMessage:        Indicates whether the stream call should go through the PostScript message.  
  238.                                     (should only be true at Imaging time when stream types are for PS)
  239.     count:                returned:  Number of prerequisite items in the list.
  240.     
  241. **************************************/
  242.     
  243. OSErr    FontDbaseBuildPrerequisiteList(TFontDbase fontDbase, scalerStreamTypeFlag streamTypes, 
  244.                                                                                     char *productDescription, Boolean useMessages, long *count)
  245.     {
  246.         OSErr                            status;
  247.         TFontDbasePtr            pDbase;
  248.         Handle                        hList;                    // Use for scratch memory to get list from scaler.
  249.         long                            scratchSize;        // size of scratch handle.
  250.         long                            nFonts;
  251.         long                            idx;
  252.         gxFont                        theFont;
  253.         scalerStream            streamRecord;
  254.         TfdbInfoFlags            fontFlags;
  255.         
  256.         *count = 0;
  257.         pDbase = *(TFontDbaseHdl)fontDbase;
  258.         
  259.         /* If there was alread a list, throw it away - we'll build a new one */
  260.         
  261.         if (pDbase->prerequisites != nil)
  262.             DisposeCollection(pDbase->prerequisites);
  263.     
  264.         /* Make a new collection for the prerequisite list */    
  265.  
  266.         pDbase = *(TFontDbaseHdl)fontDbase;
  267.         pDbase->prerequisites = NewCollection();
  268.         pDbase = *(TFontDbaseHdl)fontDbase;                    // in case memory moved.
  269.         require_action(pDbase->prerequisites, failed_NewCollection, status = MemError(););
  270.  
  271.         
  272.         pDbase->streamTypes = streamTypes;                    // Value passed in becomes current value for subsequent actions.
  273.         
  274.         /** Allocate a scratch handle for retrieving prerequisite lists **/
  275.         
  276.         status = PrNewHandle(&hList, 0);
  277.         nrequire(status, failed_AllocScratch);
  278.         scratchSize = 0;
  279.         
  280.  
  281.         /********
  282.             Loop through all of the fonts in the database.
  283.                 Get their prerequisite list
  284.                 Union it into the collection.
  285.         *********/
  286.         pDbase = *(TFontDbaseHdl)fontDbase;                    // in case memory moved.
  287.         nFonts = pDbase->numFonts;
  288.         for (idx = 1; idx <= nFonts; ++idx) {
  289.         
  290.             status = FontDbaseGetIndexedFont(fontDbase, idx, &theFont);
  291.             nrequire(status, failed_GetFont);
  292.             
  293.             /** See if we should include data for this font in the prerquisite list **/
  294.             
  295.             status = FontDbaseGetFontInfo(fontDbase, theFont, nil, nil, nil, &fontFlags);
  296.             nrequire(status, failed_GetInfo);
  297.             
  298.             /* For fonts whose prerequisites we don't exclude */
  299.             
  300.             if ( !(fontFlags & fdbExcludeFontPrereqs) ) {            
  301.             
  302.                 /** Get the size of the list **/
  303.                 
  304.                 streamRecord.types = streamTypes;
  305.                 streamRecord.targetVersion = productDescription;
  306.                 streamRecord.action = prerequisiteQueryStreamAction;
  307.                 streamRecord.variationCount = selectAllVariations;
  308.                 streamRecord.variations = nil;
  309.                 streamRecord.info.prerequisiteQuery.list = nil;
  310.                 status = FDBStreamFont(theFont, &streamRecord);
  311.                 nrequire(status, failed_sizeQuery);
  312.                 
  313.                 /* If the list size was not zero, there are prerequisites */
  314.                 
  315.                 if ( streamRecord.info.prerequisiteQuery.size > 0 ) {
  316.                                 
  317.                     /** Size the scratch space accordingly to retrieve list **/
  318.                     
  319.                     if ( streamRecord.info.prerequisiteQuery.size > scratchSize ) {
  320.                     
  321.                         scratchSize = streamRecord.info.prerequisiteQuery.size;
  322.                         status = PrSetHandleSize(hList, scratchSize);
  323.                         nrequire(status, failed_resizeScratch);
  324.                     
  325.                     }//end if
  326.         
  327.                     /** Get the list itself **/
  328.                     
  329.                     HLock(hList);
  330.                     streamRecord.info.prerequisiteQuery.list = *hList;
  331.                     status = FDBStreamFont(theFont, &streamRecord);
  332.                     nrequire(status, failed_GetList);
  333.                     
  334.                     /** Now union the list into the current collection **/
  335.                     
  336.                     status = FDBUnionPrerequisiteList((TFontDbaseHdl)fontDbase, theFont, streamRecord.info.prerequisiteQuery.size,
  337.                                                                                          (unsigned char*)*hList, count);
  338.                     nrequire(status, failed_Union);
  339.                     
  340.                     HUnlock(hList);
  341.                     
  342.                 }//end if
  343.                             
  344.             }//end if
  345.         
  346.         }//end for
  347.         
  348. failed_Union:
  349. failed_GetList:
  350. failed_resizeScratch:
  351. failed_sizeQuery:
  352. failed_GetInfo:
  353. failed_GetFont:
  354.  
  355.         /* Clean up allocations */
  356.         
  357.         DisposeHandle(hList);
  358.  
  359. failed_AllocScratch:
  360.  
  361.         /* Clean up if an error happend */
  362.         
  363.         if (status != noErr) {
  364.         
  365.             pDbase = *(TFontDbaseHdl)fontDbase;
  366.             DisposeCollection(pDbase->prerequisites);
  367.             pDbase->prerequisites = nil;
  368.             
  369.         }//end if
  370.  
  371. failed_NewCollection:
  372.             
  373.         return(status);
  374.     
  375.     }//FontDbaseBuildPrerequisiteList
  376.  
  377.  
  378.  
  379.  
  380.  
  381. /*********************************************
  382.  
  383.     Function:  FontDbaseGetIndexedPrerequisite
  384.     
  385.     Function returns information on the prerequisite in the list
  386.     based on index passed in.
  387.     
  388.     fontDbase:            the font database object.
  389.     idx:                        the index of the desired prerequisite.
  390.     size:                        (returned). Size of item.
  391.     theFont:                (returned). Font reference to use with this prerequisite.
  392.                                             Must pass nil if nil is passed for item
  393.     item:                        The prerequisite item is filled in here.
  394. **********************************************/
  395. OSErr    FontDbaseGetIndexedPrerequisite(TFontDbase fontDbase, long idx, long *size, gxFont *theFont, scalerPrerequisiteItem *item)
  396.     {
  397.         OSErr                        status;
  398.         Collection            prerequisites;    
  399.         long                        enumeration;
  400.     
  401.         prerequisites = (*(TFontDbaseHdl)fontDbase)->prerequisites;
  402.         require_action(prerequisites, failed_DontHaveCollection, if (size) *size = 0;);
  403.         
  404.         status = GetIndexedCollectionItem(prerequisites, idx, size, item);
  405.         nrequire(status, failed_GetItem);
  406.  
  407.         /*****
  408.             Since the font reference was stored in the item in place of the enumeration
  409.             and the enumeration is stored in the collection item's id, retrieve and
  410.             repair.
  411.         ******/
  412.         if ( item != nil ) {
  413.         
  414.             status = GetIndexedCollectionItemInfo(prerequisites, idx, nil, &enumeration, nil, nil);
  415.             nrequire(status, failed_GetInfo);
  416.             
  417.             if (theFont != nil)
  418.                 *theFont = (gxFont)item->enumeration;                    // we hid the font reference in here, hey it's a long too.
  419.             
  420.             item->enumeration = enumeration;                                // Put the real enumeration in here.
  421.         
  422.         }//end if
  423.  
  424. failed_GetInfo:
  425. failed_GetItem:
  426. failed_DontHaveCollection:
  427.         return(status);
  428.     
  429.     }//FontDbaseGetIndexedPrerequisite
  430.  
  431. //<FF>
  432.  
  433. static long FDBPartialSpoolProc(gxSpoolCommand command,  userSpool *block)
  434. {
  435.      OSErr            status = noErr;
  436.      
  437.    switch (command)
  438.    {
  439.       case gxOpenReadSpool:
  440.                  #if DEBUGLEVEL>0
  441.                  DebugStr("\pinvalid open read request in FDBPartialSpoolProc" );
  442.                  #endif
  443.            break;
  444.       case gxOpenWriteSpool:
  445.                  if( block->size > 0 )
  446.                      {
  447.                          block->count = 0;
  448.                          SetResourceSize( block->streamHdl, block->size );
  449.                          nrequire( status = ResError(), failed_SetResourceSize );
  450.                     }
  451.            break;      
  452.       case gxReadSpool:
  453.                  #if DEBUGLEVEL>0
  454.                  DebugStr("\pinvalid read request in FDBPartialSpoolProc" );
  455.                  #endif
  456.                  break;
  457.       case gxWriteSpool:
  458.                  check( ( block->count + block->spool.count ) <= block->size );
  459.                  WritePartialResource( block->streamHdl, block->count, block->spool.buffer, block->spool.count );
  460.                  nrequire( status = ResError(), failed_WritePartialResource );
  461.                  block->count += block->spool.count;
  462.                  break;
  463.       case gxCloseSpool:
  464.                  check( block->size == 0 || ( GetResourceSizeOnDisk( block->streamHdl ) == block->size ) );
  465.            break;
  466.    }
  467.  
  468. failed_SetResourceSize:
  469. failed_WritePartialResource:
  470.  
  471.      if (!block->saveError) block->saveError = status;
  472.  
  473.   return(status);
  474. }    
  475.     
  476.     
  477. //<FF>
  478. /*************************************************
  479.  
  480.     Function: FDBFontToHandle
  481.     
  482.     Function flattens a font into a handle.
  483.     
  484. **************************************************/
  485. OSErr FDBFontToHandle(gxFont fontID, long glyphBits[], Handle h)
  486.     {
  487.          userSpool         block;
  488.          scalerStream stream;
  489.          OSErr                status;
  490.          Handle                hBuffer;
  491.     
  492.          #if GENERATINGPOWERPC
  493.                 RoutineDescriptor    fdbPartialSpoolProc_RD = BUILD_ROUTINE_DESCRIPTOR(uppgxSpoolProcInfo, FDBPartialSpoolProc);
  494.                 gxSpoolUPP                fdbPartialSpoolProc_UPP = (gxSpoolUPP) &fdbPartialSpoolProc_RD;
  495.          #else
  496.                 gxSpoolUPP                fdbPartialSpoolProc_UPP = (gxSpoolUPP) FDBPartialSpoolProc;
  497.          #endif
  498.  
  499.          check (h);
  500.                   
  501.          block.streamHdl = h;
  502.          block.count = 0;
  503.          block.size = 0;
  504.          block.saveError = noErr;
  505.  
  506.          #define flatBufferSize        4096
  507.             
  508.          nrequire( status = PrNewHandle( &hBuffer, flatBufferSize ), NewBufferFailed );
  509.          
  510.          HLock( hBuffer ); block.spool.buffer = *hBuffer;
  511.          
  512.          block.spool.bufferSize = flatBufferSize;
  513.          
  514.          #undef flatBufferSize
  515.          
  516.          block.spool.spoolProcedure = fdbPartialSpoolProc_UPP;
  517.     
  518.          stream.streamRefCon = fontID;
  519.          stream.types = flattenedStreamType;
  520.          stream.action = fontSizeQueryStreamAction;
  521.          stream.memorySize = 0;
  522.          stream.variationCount = selectAllVariations;
  523.          stream.variations = nil;
  524.          stream.info.font.encoding = nil;
  525.          stream.info.font.glyphBits = glyphBits;
  526.          stream.info.font.name = nil;
  527.         
  528.          GXFlattenFont(fontID, &stream, &block.spool);
  529.  
  530.          status = GXGetGraphicsError(nil);
  531.          nrequire(status, failed_flatten);
  532.          
  533.          check( stream.memorySize > 0 );
  534.          
  535.          block.size = stream.memorySize;
  536.          stream.action = downloadStreamAction;
  537.         
  538.          GXFlattenFont(fontID, &stream, &block.spool);
  539.  
  540.          status = GXGetGraphicsError(nil);
  541.          nrequire(status, failed_flatten);
  542.          
  543. failed_flatten:         
  544.          HUnlock( hBuffer );
  545. NewBufferFailed:                
  546.          DisposeHandle( hBuffer );
  547.  
  548.          if (block.saveError != noErr)        /* Get the error that we generated in our spool proc */
  549.              status = block.saveError;
  550.  
  551.          return(status);
  552.  
  553.     }//FDBPrereqToHandle
  554.     
  555.     
  556.     /*************************************************
  557.  
  558.     Function: FDBPrereqToHandle
  559.     
  560.     Function flattens a prerequisite item into a handle.
  561.     
  562. **************************************************/
  563. OSErr FDBPrereqToHandle(gxFont fontID, scalerPrerequisiteItem *item, Handle h)
  564.     {
  565.          userSpool block;
  566.          scalerStream stream;
  567.          OSErr                status;
  568.          Handle        hBuffer;
  569.          
  570.          #if GENERATINGPOWERPC
  571.                 RoutineDescriptor    fdbPartialSpoolProc_RD = BUILD_ROUTINE_DESCRIPTOR(uppgxSpoolProcInfo, FDBPartialSpoolProc);
  572.                 gxSpoolUPP                fdbPartialSpoolProc_UPP = (gxSpoolUPP) &fdbPartialSpoolProc_RD;
  573.          #else
  574.                 gxSpoolUPP                fdbPartialSpoolProc_UPP = (gxSpoolUPP) FDBPartialSpoolProc;
  575.          #endif
  576.  
  577.          check (h);
  578.          check( item->size > 0 );         
  579.          block.streamHdl = h;
  580.          block.size = item->size;
  581.          block.count = 0;
  582.          block.saveError = noErr;
  583.  
  584.          #define flatBufferSize        512
  585.             
  586.          nrequire( status = PrNewHandle( &hBuffer, flatBufferSize ), NewBufferFailed );
  587.          
  588.          HLock( hBuffer ); block.spool.buffer = *hBuffer;
  589.          
  590.          block.spool.bufferSize = flatBufferSize;
  591.          
  592.          #undef flatBufferSize
  593.          
  594.          block.spool.spoolProcedure = fdbPartialSpoolProc_UPP;
  595.     
  596.          stream.streamRefCon = fontID;
  597.          stream.types = flattenedStreamType;
  598.          stream.action = prerequisiteItemStreamAction;
  599.          stream.memorySize = 0;
  600.          stream.variationCount = selectAllVariations;
  601.          stream.variations = nil;
  602.          stream.info.prerequisiteItem = item->enumeration;
  603.  
  604.          GXFlattenFont(fontID, &stream, &block.spool);
  605.     
  606.          status = GXGetGraphicsError(nil);
  607.          nrequire(status, failed_flatten);
  608.          
  609. failed_flatten:         
  610.          HUnlock( hBuffer );
  611. NewBufferFailed:                
  612.          DisposeHandle( hBuffer );
  613.  
  614.          if (block.saveError != noErr)        /* Get the error that we generated in our spool proc */
  615.              status = block.saveError;
  616.  
  617.          return(status);
  618.  
  619.     }//FDBPrereqToHandle
  620.  
  621.  
  622. #if !GXTOPOSTSCRIPTLIBRARY
  623. /*-----------------------------------------------------------------------------------
  624.  
  625.     CreatePartialStreamTempFile
  626.     
  627.         this routines creates a file into which we can stream a partial font
  628.         
  629. -----------------------------------------------------------------------------------*/
  630. OSErr CreatePartialStreamTempFile( TFile *filerefPtr, Handle *streamHdlPtr )
  631. {
  632.     OSErr            status;
  633.     
  634.     TFile         fileref = nil;
  635.     Handle        streamHdl = nil;
  636.     FSSpec        spec;
  637.     
  638.     nrequire( status = FindFolder( kOnSystemDisk, kTemporaryFolderType, kCreateFolder, 
  639.         & spec.vRefNum, & spec.parID ), FindTempFolderFailed );
  640.     
  641.     /* the following string does not need to be localized so it is ok to leave it as is */
  642.  
  643.     #define        TempStreamFileName        "\pGX Printing Temp"
  644.     
  645.     check( sizeof( TempStreamFileName ) < 32 );
  646.     
  647.     BlockMove( TempStreamFileName, spec.name, sizeof( TempStreamFileName ) );
  648.  
  649.     #undef TempStreamFileName
  650.     
  651.     nrequire( status = FHNewFileReference( &fileref ), NewFileRefFailed );
  652.     nrequire( status = FHCreateFile( fileref, &spec, true ), CreateFileFailed );
  653.     
  654.     // creating the file also opens it -- how weird
  655.     
  656.     nrequire( status = PrNewHandle( &streamHdl, 0 ), NewHandleFailed );
  657.  
  658.     nrequire( status = FHAddResource( fileref, streamHdl, 'TEMP', 128 ), AddResourceFailed );
  659.     SetResAttrs( streamHdl, resPurgeable );        
  660.     WriteResource( streamHdl ); nrequire( status = ResError(), WriteResourceFailed );
  661.     
  662.     HPurge( streamHdl );
  663.     EmptyHandle( streamHdl );            /* purge the handle */
  664.  
  665.     check( *streamHdl == nil );                                    /* check that it has been purged */
  666.     
  667.     *streamHdlPtr = streamHdl;
  668.     *filerefPtr = fileref;
  669.  
  670.     return( noErr );    
  671.  
  672. AddResourceFailed:    
  673.     (void) PrDisposeHandle( streamHdl );
  674. GetPurgeHandleFailed:
  675. WriteResourceFailed: ReleaseStreamFailed: NewHandleFailed:
  676. OpenFileFailed:
  677.     (void) FHCloseFile( fileref, false );
  678. CreateFileFailed:
  679.     (void) FHDeleteFile( fileref );
  680.  
  681. NewFileRefFailed:
  682. FindTempFolderFailed:
  683.     return( status );
  684. }
  685.  
  686. /*-----------------------------------------------------------------------------------
  687.  
  688.     DisposePartialStreamTempFile
  689.     
  690.         this routine gets rid of the file that we created above
  691.         
  692. -----------------------------------------------------------------------------------*/
  693. void DisposePartialStreamTempFile( TFile fileref, Handle streamHdl )
  694. {    
  695.     check( fileref );
  696.     check( streamHdl );
  697.     check( *streamHdl == nil );
  698.     
  699.     (void) FHReleaseResource(    fileref, streamHdl );
  700.     
  701.     // somehow you can only delete an opened file -- how weird
  702.     (void) FHDeleteFile( fileref );
  703.     (void) FHDisposeFileReference( fileref );
  704. }
  705.  
  706. #endif
  707.